package com.luobd.bpm.business.process.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luobd.bpm.business.process.dto.ProcessXmlDto;
import com.luobd.bpm.business.process.entity.CoreProcessDef;
import com.luobd.bpm.business.process.input.DeployProcessInput;
import com.luobd.bpm.business.process.input.ProcessDefinitionInput;
import com.luobd.bpm.business.process.input.ProcessDefinitionPageQueryInput;
import com.luobd.bpm.business.process.mapper.ProcessDefMapper;
import com.luobd.bpm.business.process.service.IProcessDefService;
import com.luobd.bpm.common.ResponseData;
import com.luobd.bpm.common.ResponsePageData;
import com.luobd.bpm.common.utils.BpmnUtil;
import com.luobd.bpm.dto.ProcessDefinitionDTO;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.stream.Collectors;

@Service
@Primary
public class ProcessDefServiceImpl extends ServiceImpl<ProcessDefMapper, CoreProcessDef> implements IProcessDefService {



    @Autowired
    private RepositoryService repositoryService;







    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseData<Long> saveOrUpdate(ProcessDefinitionInput input) {
        CoreProcessDef coreProcessDef;
        QueryWrapper<CoreProcessDef> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("processKey",input.getProcessKey());
        queryWrapper.notIn(input.getId() != null,"id",input.getId());
        if(this.count(queryWrapper) > 0) {
            return ResponseData.error("流程定义key已存在");
        }
        if(input.getId() == null){
            coreProcessDef = new CoreProcessDef();
            coreProcessDef.setStatus(CoreProcessDef.ProcessStatus.DRAFT.getCode());
        }else {
            CoreProcessDef definition = this.getById(input.getId());
            if(definition == null) {
                return ResponseData.error("流程定义不存在");
            }
            coreProcessDef = definition;
        }
        coreProcessDef.setName(input.getName());
        coreProcessDef.setProcessKey(input.getProcessKey());
        coreProcessDef.setRemark(input.getRemark());
        coreProcessDef.setCategory(input.getCategory());
        if(!this.saveOrUpdate(coreProcessDef)) {
            return ResponseData.error("保存失败");
        }
        return ResponseData.success(coreProcessDef.getId());
    }

    @Override
    public ResponsePageData<ProcessDefinitionDTO> page(ProcessDefinitionPageQueryInput input) {
        QueryWrapper<CoreProcessDef> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(input.getCategory()),"category",input.getCategory());
        queryWrapper.like(StrUtil.isNotBlank(input.getKey()),"processKey",input.getKey());
        queryWrapper.like(StrUtil.isNotBlank(input.getName()),"name",input.getName());
        queryWrapper.eq(input.getStatus() != null,"status",input.getStatus());
        Page<CoreProcessDef> page = this.page(new Page<>(input.getPageNum(), input.getPageSize()), queryWrapper);
        return ResponsePageData.success(page.getRecords().stream()
                .map(ProcessDefinitionDTO::new)
                .collect(Collectors.toList()),page.getTotal());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseData<String> deployment(DeployProcessInput input) {
        CoreProcessDef   def = this.getById(input.getProcessDefId());
        if(def == null) {
            return ResponseData.error("流程定义不存在");
        }
        String id = repositoryService.createDeployment().name(def.getName())
                .key(def.getProcessKey())
                .category(def.getCategory())
                .addString(def.getProcessKey() + ".bpmn20.xml", input.getBpmnXml())
                .deploy().getId();
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(id).singleResult();
        def.setProcessDefinitionId(definition.getId());
        def.setStatus(CoreProcessDef.ProcessStatus.RELEASE.getCode());
        def.setVersion(def.getVersion() == null ? 1 : def.getVersion() + 1);
        def.setXml(input.getBpmnXml());
        this.updateById(def);
        return ResponseData.success(id);
    }

    @Override
    public ResponseData<ProcessXmlDto> getProcessXml(Long id) {
        CoreProcessDef def = this.getById(id);
        if(def == null) {
            return ResponseData.error("流程定义不存在");
        }
        ProcessXmlDto dto = new ProcessXmlDto();
        dto.setBpmnXml(def.getXml());
        dto.setProcessDefinitionId(def.getProcessDefinitionId());
        dto.setId(def.getId());
        if(StrUtil.isNotBlank(def.getProcessDefinitionId())) {
            dto.setBpmnModel(repositoryService.getBpmnModel(def.getProcessDefinitionId()));
        }
        return ResponseData.success(dto);
    }

    @Override
    public ResponseData<ProcessXmlDto> getProcessXml(String id) {
        QueryWrapper<CoreProcessDef> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("processDefinitionId",id);
        CoreProcessDef def = this.getOne(queryWrapper);
        if(def == null) {
            return ResponseData.error("流程定义不存在");
        }
        ProcessXmlDto dto = new ProcessXmlDto();
        dto.setBpmnXml(def.getXml());
        dto.setProcessDefinitionId(def.getProcessDefinitionId());
        dto.setId(def.getId());
        if(StrUtil.isNotBlank(def.getProcessDefinitionId())) {
            dto.setBpmnModel(repositoryService.getBpmnModel(def.getProcessDefinitionId()));
            String xml = BpmnUtil.model2Xml(dto.getBpmnModel());
        }


        return ResponseData.success(dto);
    }

    @Override
    public ResponseData<Boolean> delete(Long id) {
        CoreProcessDef processDef = this.getById(id);
        if(processDef == null) {
            return ResponseData.error("流程定义不存在");
        }
        ProcessDefinition result = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDef.getProcessDefinitionId()).singleResult();
        if(result == null) {
            return ResponseData.error("流程定义不存在");
        }
        repositoryService.deleteDeployment(result.getDeploymentId(),true);
        this.removeById(id);
        return ResponseData.success(Boolean.TRUE);
    }


}
